package cn.tedu.submarine;
import javax.swing.JFrame;
import javax.swing.JPanel;//1.
import java.awt.Graphics;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Random;
import java.util.Arrays;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
/**  整个游戏窗口*/
public class World extends JPanel{ //2.
   public static final int WIDTH = 641; //窗口的宽
   public static final int HEIGHT = 479; //窗口的高

    public static final int START = 0;//启动状态
    public static final int RUNNING = 1;//运行状态
    public static final int GAME_OVER = 2;//游戏结束状态
    private int state = START;//当前状态（默认为启动状态）

  //窗口中显示的对象
    private  Battleship ship = new Battleship(); //战舰
    private  SeaObject[] submarines = {

    };   //潜艇数组（侦察潜艇、鱼雷潜艇、水雷潜艇）
    private  SeaObject[] thunders = {

    };   //雷数组（鱼雷、水雷）
    private  Bomb[] bombs = {

    };  //深水炸弹数组

    /** 生成潜艇（侦察潜艇、鱼雷潜艇、水雷潜艇）对象*/
    public SeaObject nextSubmarine(){

         Random rand = new Random();//随机数对象
         int type = rand.nextInt(20);//0到19
        if(type<10){//0到9时，返回侦察艇对象
            return new ObserveSubmarine();
        }else if(type<15){//10到14时，返回鱼雷潜艇对象
            return new TorpedoSubmarine();
        }else{//15到19时，返回水雷潜艇对象
            return new MineSubmarine();
        }
    }

    private int subEnterIndex = 0;
    /** 潜艇入场 */
    public void submarineEnterAction() {//每10毫秒走一次
        subEnterIndex++;
        if (subEnterIndex % 40 == 0) {//每400（10*40）毫秒走一次
            SeaObject obj = nextSubmarine();//获取潜艇对象
            submarines = Arrays.copyOf(submarines, submarines.length + 1);
            submarines[submarines.length - 1] = obj;//将obj添加到submarines的最后一个元素后
        }
    }


       private int thunderEnterIndex = 0;//雷入场计数
        /** 雷（鱼雷、水雷）入场*/
        public void thunderEnterAction(){//每10毫秒走一次
            thunderEnterIndex++;//每10毫秒增1
            if(thunderEnterIndex%100==0){//每1000毫秒（10*100）走一次
            for(int i=0;i<submarines.length;i++){//遍历所有潜艇
              SeaObject obj =  submarines[i].shootThunder();//潜艇发射雷
                if(obj!=null){//若有雷
                    thunders = Arrays.copyOf(thunders,thunders.length+1);
                    thunders[thunders.length-1] = obj;//将obj添加到最后一个元素上

                }
            }
            }
        }

   /** 海洋对象移动*/
   public void stepAction(){//每10毫秒走一次
       for(int i=0;i<submarines.length;i++){//遍历所有潜艇
           submarines[i].step();//潜艇动
       }
       for(int i=0;i<thunders.length;i++){
           thunders[i].step();//雷动
       }
       for(int i=0;i<bombs.length;i++){
           bombs[i].step();//深水炸弹动
       }

   }

   /** 删除越界的海洋对象-----避免内存泄漏*/
    public void outOfBoundsAction(){//每10毫秒走一次
         for(int i=0;i<submarines.length;i++){
             if(submarines[i].isOutOfBounds()|| submarines[i].isDead()){
                 submarines[i] = submarines[submarines.length-1];
                 submarines = Arrays.copyOf(submarines,submarines.length-1);
             }
         }

         for(int i=0;i<thunders.length;i++){//遍历所有雷
             if(thunders[i].isOutOfBounds() ||thunders[i].isDead() ){//越界了
                 thunders[i] = thunders[thunders.length-1];//将越界雷替换为最后一个元素
                 thunders = Arrays.copyOf(thunders,thunders.length-1);//缩容
             }
         }

         for(int i=0;i<bombs.length;i++){//遍历所有深水炸弹
             if(bombs[i].isOutOfBounds() || bombs[i].isDead()){
                 bombs[i] = bombs[bombs.length-1];
                 bombs = Arrays.copyOf(bombs,bombs.length-1);
             }
         }
    }

    private int score = 0;//玩家的得分
/**  深水炸弹与潜艇的碰撞 */
  public void bombBangAction(){//每10毫秒走一次
      for(int i=0;i<bombs.length;i++){//遍历所有深水炸弹
          Bomb b = bombs[i];//获取每一个深水炸弹
          for(int j=0;j<submarines.length;j++){//遍历所有潜艇
              SeaObject s = submarines[j];//获取每一个潜艇
              if(b.isLive() && s.isLive() && s.isHit(b)){
                  s.goDead();//潜艇去死
                  b.goDead();//深水炸弹去死


                  if(s instanceof EnemyScore){//若被撞潜艇能得分
                      EnemyScore es = (EnemyScore)s;//将被撞潜艇强转为得分接口
                      score += es.getScore();//玩家得分
                  }
                  if(s instanceof EnemyAward ){//若被撞潜艇能得命
                      EnemyAward ea = (EnemyAward)s;//将被撞潜艇强转为得命接口
                      int num = ea.getLife();//获取命数
                      ship.addLife(num);//战舰得命

                  }


              }
          }

      }

  }

   /** 雷与战舰的碰撞 */
  public void thunderBangAction(){//每10毫秒走一次
       for(int i=0;i<thunders.length;i++){//遍历所有的雷
           SeaObject t = thunders[i];//获取每一个雷
           if(t.isLive() && ship.isLive() && t.isHit(ship)){//若都活着并且还撞上了
               t.goDead();//雷去死
               ship.subtractLife();//战舰减命
           }
       }
  }

 /** 检测游戏结束 */
  public void checkGameOverAction(){//每10毫秒走一次
      if(ship.getLife()<=0){//若战舰的命数《=0，表示游戏结束了，则。。。
             state = GAME_OVER;//则当前状态修改为GAME——OVER游戏结束状态
      }
        }

    /**  启动程序的执行 */
    public void action(){//
       //如下为侦听器的代码
        KeyAdapter k = new KeyAdapter() {
            /**  重写keyReleased()键盘弹起事件*/
            public void keyReleased(KeyEvent e) {
                if(e.getKeyCode()==KeyEvent.VK_SPACE){//若按下的是空格键
                     switch(state){//根据当前的状态做不同的处理
                         case START://启动状态时
                             state = RUNNING;//修改为运行状态
                             break;
                         case RUNNING://运行状态时
                             Bomb obj = ship.shoot();//获取战舰发射出来的深水炸弹
                             bombs = Arrays.copyOf(bombs,bombs.length+1);
                             bombs[bombs.length-1] = obj;//将obj添加到最后一个元素上
                             break;
                         case GAME_OVER://游戏结束状态时
                             score = 0;  //清理现场（数据归零）
                             ship = new Battleship();
                             submarines = new SeaObject[0];
                             thunders = new SeaObject[0];
                             bombs = new Bomb[0];

                         state = START;//修改为启动状态
                     }
                }

                if(e.getKeyCode()==KeyEvent.VK_LEFT){//若按下的是左键
                    ship.moveLeft();//战舰左移
                }
                if(e.getKeyCode()==KeyEvent.VK_RIGHT){//若按下的是右键
                    ship.moveRight();//战舰右移
                }
            }
        };//键盘侦听器
        this.addKeyListener(k);//将键盘侦听器添加到当前窗口上


        Timer timer = new Timer();//定时器对象
        int intervel = 10;//定时间隔（以毫秒为单位）
        timer.schedule(new TimerTask() {

            /**重写run()方法*/
            public void run() {//定时干的事----每10毫秒自动执行
               if(state==RUNNING){
                   submarineEnterAction();//潜艇入场
                   thunderEnterAction();  //雷入场
                   stepAction(); //海洋对象移动
                   outOfBoundsAction();//删除越界的海洋对象
                   bombBangAction();  //深水炸弹与潜艇的碰撞
                   thunderBangAction();//雷与战舰的碰撞
                   checkGameOverAction();//检测游戏结束
               }
                repaint(); //重画（重新调用paint()方法）
            }
        }, intervel, intervel);//定时计划
    }
     /**重写paint()画  g:画笔*/
    public void paint(Graphics g){
        switch(state){//根据当前的状态做不同的处理
            case START://启动状态时画启动图
                Images.start.paintIcon(null,g,0,0);
                break;
            case GAME_OVER:
                Images.gameover.paintIcon(null,g,0,0);
                break;
            case RUNNING:
                Images.sea.paintIcon(null,g,0,0);//画海洋图
                ship.paintImage(g);//画战舰
                for(int i=0;i<submarines.length;i++){//遍历所有潜艇
                    submarines[i].paintImage(g);//画潜艇
                }
                for(int i=0;i<thunders.length;i++){
                    thunders[i].paintImage(g);//画雷
                }
                for(int i=0;i<bombs.length;i++){
                    bombs[i].paintImage(g);//画深水炸弹
                }

                g.drawString("SCORE："+score,200,50);//画分
                g.drawString("LIFE:"+ship.getLife(),400,50);//画命

        }



    }



    public static void main(String[] args) {
          JFrame frame = new JFrame();
          World world = new World();
          world.setFocusable(true);
          frame.add(world);
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setSize(WIDTH+16,HEIGHT+39);
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);//1)设置窗口可见 2）尽快调用paint()方法
          world.action();//启动程序的执行

    }
}


/*
       1.问：为什么将那一堆引用设计在main的外面？
       答：若将引用设计在main中，意味着引用就只能在main中访问了
       而world类后期会设计很多的方法，这些方法中都需要操作那一堆引用
       所以将引用设计在main的外面，以扩大作用范围

       2.问：为什么要单独创建action方法做测试？
       答：因为main是static的，在static的方法中是无法访问那一堆引用的
       所以单独创建一个非static的方法action()来测试

        3.问：在main中为什么要先创建World对象，再调用action()方法？
        答：因为main是static的，在static方法中是无法直接调用action()方法的
        所以先创建World对象，再调用action（）方法


 */